pub mod json_codec;
pub mod binary_codec;
pub mod primary_codec;

use std::any::{Any};
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::Arc;
use crate::{RpcContext, RpcResult};
use crate::dto::{RpcData, RpcHeader};

/// 解析普通对象
pub trait RpcEncode: Any {
    fn encode(&self, context: &RpcContext) -> RpcResult<Vec<u8>>;
}


/// 编码集合器
#[derive(Debug, Clone)]
pub struct RpcCodecGather {
    pub codec_type_map: Arc<HashMap<String, Box<dyn Any>>>,
}

unsafe impl Send for RpcCodecGather {}
unsafe impl Sync for RpcCodecGather {}

impl RpcCodecGather {
    pub fn new(codec_type_map: HashMap<String, Box<dyn Any>>) -> Self {
        Self {
            codec_type_map: Arc::new(codec_type_map),
        }
    }

    pub fn has_codec_type(&self, codec_type: &str) -> bool {
        self.codec_type_map.contains_key(codec_type)
    }

    pub fn get_codec_factory(&self, codec: &str) -> Option<&Box<dyn Any>> {
        let data = self.codec_type_map.get(codec);
        data
    }

    pub fn codec_by_type<T: 'static, F: Fn(Option<&Box<dyn RpcCodec<T>>>)>(&self, codec_type: String, handle: F) -> RpcResult<()> {
        let data = self.codec_type_map.get(&codec_type);
        match data {
            None => {
                handle(None);
            }
            Some(data) => {
                if let Some(data) = data.downcast_ref::<Box<dyn RpcCodec<T>>>() {
                    handle(Some(data));
                } else {
                    handle(None)
                }
            }
        }
        Ok(())
    }
}

pub trait RpcCodecHeader: Any {
    fn encode_header(&self, header: &RpcHeader) -> RpcResult<Vec<u8>>;

    fn decode_header(&self, data: &Vec<u8>) -> RpcResult<(RpcHeader, Vec<u8>)>;

    fn encode_data(&self, header: &RpcHeader, data: &Vec<u8>) -> RpcResult<Vec<u8>>;
}

pub trait RpcCodec<T>: RpcCodecHeader {
    fn encode(&self, data: &T) -> RpcResult<Vec<u8>>;

    fn decode(&self, data: Vec<u8>) -> RpcResult<T>;

    fn encode_rpc_data(&self, data: &RpcData<T>) -> RpcResult<Vec<u8>>;
}

pub trait RpcCodecFactory<T>: Any {
    fn create()-> Box<dyn RpcCodec<T>>;
}

